import {NodeWrapper, Stage} from "./vo";

export interface Point {
  x: number
  y: number
}

export interface Bounds {
  x: number
  y: number
  w: number
  h: number
}

export interface HtmlNodeOptions {
  tag?: string
  autoSetupEl?: boolean
}

export interface INodeImpl<T = NodeWrapper> {
  setup(ctx: IContext): HTMLElement

  hooks?: {
    create?(this: NodeWrapper & T): void

    update?(this: NodeWrapper & T, props?: Record<string, any>): void

    resize?(this: NodeWrapper & T): void

    themeChanged?(this: NodeWrapper & T, theme: ThemeName, props?: Record<string, any>): void

    destroy?(this: NodeWrapper & T): void
  }
}

export type NodeImplFactory = (nodeData: INodeData) => INodeImpl

export interface IContext {
  options: ICreateStageOptions
  theme: ThemeName
  stage: Stage
  editMode: boolean
}

export type ThemeName = 'light' | 'dark' | string

export interface ICreateStageOptions {
  el: string | HTMLElement
  nodes?: INodeData[]
  nodeImplFactoryMap?: Record<string, NodeImplFactory>
  theme?: ThemeName
  autoResize?: boolean
  editMode?: boolean
  designBounds?: Bounds
  onHistoryChange?: (command: Command) => void
  onHoverNode?: (node?: NodeWrapper) => void
  onSelectionChange?: (selections: number[]) => void
  onAddNode?: (node: INodeData) => void
  onRemoveNode?: (node: INodeData) => void
}

export interface INodeData {
  id?: number
  pid?: number
  nodeType: string
  label: string
  bounds?: Bounds
  locked?: boolean
  visible?: boolean

  props?: Record<string, any>
}

export type ICreateNodeData = Partial<INodeData> & Required<Pick<INodeData, 'label' | 'bounds'>>

export interface CtrlElement extends HTMLElement {
  'data-type': string
}

export type DataSet = Record<string, any>

export enum CommandType {
  MODIFY_NODES,
  SELECT_NODES,
  ADD_NODE,
  REMOVE_NODE,
}

export type ActionType = 'redo' | 'undo'

export interface ModifyNodeParam {
  node: NodeWrapper
  data?: DataSet
  oldData?: DataSet
}

export interface Command {
  type: CommandType
  undo: () => void
  redo: () => void
}

export type ActionCallback = (commandType: CommandType, actionType: ActionType) => void
export type HistoryChangeCallback = (command: Command) => void

export interface SelectNodeOptions{
  multiMode?: boolean
  toggleMode?: boolean
  unselect?: boolean
  updateSelection?: boolean
  changeHistory?: boolean
}
